-- Copyright 2007-2009 Google Inc.
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- glue for C-based fuzzer

drop function generate_regex();
CREATE FUNCTION generate_regex() RETURNS text
AS '/tmp/fuzzer', 'generate_regex'
   LANGUAGE C STRICT;

drop function get_seed();
CREATE FUNCTION get_seed() RETURNS integer
AS '/tmp/fuzzer', 'get_seed'
   LANGUAGE C STRICT;

drop function re_seed(integer);
CREATE FUNCTION re_seed(integer) RETURNS void
AS '/tmp/fuzzer', 're_seed'
LANGUAGE C STRICT;





CREATE LANGUAGE plpgsql;

-- fuzz()
--
-- Fuzzes the REGEXP command using random regular expressions
-- generated by generate_regex()
CREATE OR REPLACE FUNCTION cfuzz(s integer, iterations BIGINT, progress_cnt BIGINT, length_bias INTEGER) RETURNS INTEGER AS $$
DECLARE
  -- Setup an exception handler for regexp errors (1139)
  re TEXT := '';
  bad INTEGER := 0;
  count INTEGER := 0;
  matches INTEGER := 0;
  nomatches INTEGER := 0;
  matched boolean;
  current_seed BIGINT;
BEGIN

  -- Set the seed to the user-specified seed
  PERFORM re_seed(s);


  WHILE count < iterations LOOP
    IF (count % progress_cnt) = 0 THEN
      current_seed := get_seed();
      RAISE INFO 'count: % last seed: % matches: % nomatches: % bad: % last re: %', count, current_seed, matches, nomatches, bad, re;
    END IF;
    re := generate_regex();
    -- TODO: add support to exercise multi-byte regex matches
    BEGIN
      SELECT INTO matched re ~ re;
      IF matched = 't' THEN
        matches := matches + 1;
      ELSE
        nomatches := nomatches + 1;
      END IF;

    EXCEPTION WHEN invalid_regular_expression THEN
        bad := bad + 1;
    END;
    count := count + 1;
  END LOOP;
  RETURN 0;
END;
$$ LANGUAGE plpgsql;
